home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Utilities / Winter Shell 1.0d2 / Source / Libraries / DrawLib / DrawLib.c next >
Encoding:
C/C++ Source or Header  |  1994-01-10  |  13.7 KB  |  509 lines  |  [TEXT/KAHL]

  1. /* Functions for drawing things using QuickDraw and for changing attributes
  2.     of graf ports.
  3.     
  4.     Revision History:
  5.     
  6.     94/01/02 aih
  7.     - added function to set color hilite mode
  8.     
  9.     93/12/02 aih
  10.     - added functions for dragging rectangles and regions
  11.     
  12.     93/11/17 aih
  13.     - moved InvalXor from TextScrollLib.c
  14.     
  15.     93/11/15 aih
  16.     - added function to convert a region from global to local coordinates
  17.     
  18.     92/03/20 AIH
  19.     - Added function to draw a small icon
  20.     
  21.     92/02/26 AIH
  22.     - Removed patch to SetCursor since it didn't do much for efficiency
  23.     
  24.     92/02/20 AIH
  25.     - Added function to draw thick input focus border
  26.     
  27.     91/05/15 AIH
  28.     - Added patch to SetCursor to improve the efficiency of the cursor
  29.     setting function
  30.         
  31.     91/05/14 AIH
  32.     - Improved efficiency of function for setting the cursor
  33.     
  34.     91/04/05 AIH
  35.     - Added function to convert a local region to a global region.
  36.     This function doesn't start with the prefix 'Draw', but I decided
  37.     that's ok since its relationship to the ToolBox routine LocalToGlobal
  38.     is obvious, and therefore its relationship to QuickDraw should also
  39.     obvious. Besides, I couldn't think of a better name.
  40.     
  41.     91/03/25 AIH
  42.     - Added function to determine if the cursor was changed
  43.     - Added constant for the arrow cursor
  44.     
  45.     91/03/17-18 AIH
  46.     - Ifdef'd out unused functions
  47.     - Added a few comments.
  48.     
  49.     91/02/27 AIH
  50.     - Added functions for creating a big port and for dragging a rectangle
  51.     
  52.     91/02/26 AIH
  53.     - Moved function for drawing an icon at a random position into this
  54.     file from the blackout library
  55.     
  56.     91/02/08 AIH
  57.     - Removed some more functions that weren't really needed
  58.     
  59.     91/01/21 AIH
  60.     - Removed some functions I never use
  61.     
  62.     91/01/05 Ari Halberstadt (AIH)
  63.     - Inserted this standard header in all files */
  64.  
  65. #include <limits.h>
  66. #include <stdlib.h>
  67. #include "DrawLib.h"
  68. #include "MemoryLib.h"
  69. #include "RectangleLib.h"
  70. #include "ScreenLib.h"
  71.  
  72. /*----------------------------------------------------------------------*/
  73. /* hilite mode */
  74. /*----------------------------------------------------------------------*/
  75.  
  76. /* set hilite mode for color hiliting (IM-V, p61) */
  77. void SetHiliteMode(void)
  78. {
  79.     #define HiliteMode (*(char *) (0x938))
  80.     BitClr(&HiliteMode, pHiliteBit);
  81. }
  82.  
  83. /*----------------------------------------------------------------------*/
  84. /* setting the cursor */
  85. /*----------------------------------------------------------------------*/
  86.  
  87. /* Set the cursor with the given resource ID. To set to the arrow
  88.     cursor use the constant arrowCursor. */
  89. void DrawCursor(short id)
  90. {
  91.     CursHandle crsr = NULL;
  92.     
  93.     if (id == arrowCursor)
  94.         SetCursor(&arrow);
  95.     else {
  96.         crsr = GetCursor(id);
  97.         if (crsr && *crsr)
  98.             SetCursor(*crsr); /* won't move or purge memory */
  99.     }
  100. }
  101.  
  102. /*----------------------------------------------------------------------*/
  103. /* manipulating regions */
  104. /*----------------------------------------------------------------------*/
  105.  
  106. /* convert region to global coordinates */
  107. void LocalToGlobalRgn(RgnHandle rgn)
  108. {
  109.     Point origin = { 0, 0 };
  110.  
  111.     LocalToGlobal(&origin);
  112.     OffsetRgn(rgn, origin.h, origin.v);
  113. }
  114.  
  115. /* convert region to local coordinates */
  116. void GlobalToLocalRgn(RgnHandle rgn)
  117. {
  118.     Point origin = { 0, 0 };
  119.  
  120.     LocalToGlobal(&origin);
  121.     OffsetRgn(rgn, -origin.h, -origin.v);
  122. }
  123.  
  124. /* convert region to global coordinates */
  125. void PortToGlobalRgn(RgnHandle rgn, GrafPtr port)
  126. {
  127.     GrafPtr svport;
  128.     
  129.     GetPort(&svport);
  130.     SetPort(port);
  131.     LocalToGlobalRgn(rgn);
  132.     SetPort(svport);
  133. }
  134.  
  135. /* convert region to port coordinates */
  136. void GlobalToPortRgn(RgnHandle rgn, GrafPtr port)
  137. {
  138.     GrafPtr svport;
  139.     
  140.     GetPort(&svport);
  141.     SetPort(port);
  142.     GlobalToLocalRgn(rgn);
  143.     SetPort(svport);
  144. }
  145.  
  146. /*----------------------------------------------------------------------*/
  147. /* manipulating points */
  148. /*----------------------------------------------------------------------*/
  149.  
  150. /* convert a global coordinate to the port's coordinate */
  151. void GlobalToPort(Point *pt, GrafPtr port)
  152. {
  153.     GrafPtr oldPort;
  154.     GetPort(&oldPort);
  155.     SetPort(port);
  156.     GlobalToLocal(pt);
  157.     SetPort(oldPort);
  158. }
  159.  
  160. /* convert a port coordinate to the global coordinate */
  161. void PortToGlobal(Point *pt, GrafPtr port)
  162. {
  163.     GrafPtr oldPort;
  164.     GetPort(&oldPort);
  165.     SetPort(port);
  166.     LocalToGlobal(pt);
  167.     SetPort(oldPort);
  168. }
  169.  
  170. /*----------------------------------------------------------------------*/
  171. /* Functions for getting and setting text attributes of the current port.
  172.     These are similar to the ToolBox procedures GetPenState, SetPenState,
  173.     and PenNormal. */
  174. /*----------------------------------------------------------------------*/
  175.  
  176. /* get the text attributes */
  177. void GetTextState(TextState *text)
  178. {
  179.     GrafPtr port;
  180.     
  181.     GetPort(&port);
  182.     text->font = port->txFont;
  183.     text->face = port->txFace;
  184.     text->mode = port->txMode;
  185.     text->size = port->txSize;
  186. }
  187.  
  188. /* set the text attributes */
  189. void SetTextState(const TextState *text)
  190. {
  191.     TextFont(text->font);
  192.     TextFace(text->face);
  193.     TextMode(text->mode);
  194.     TextSize(text->size);
  195. }
  196.  
  197. /* set the text attributes to their defaults */
  198. void TextNormal(void)
  199. {
  200.     TextFont(0);
  201.     TextFace(0);
  202.     TextSize(0);
  203.     TextMode(srcOr);
  204. }
  205.  
  206. /*----------------------------------------------------------------------*/
  207. /* drawing icons */
  208. /*----------------------------------------------------------------------*/
  209.  
  210. /* Draw a SICN, a resource type which defines a 16 by 16 bit image,
  211.     at the given location. SICN is specified by a resource ID number
  212.     and a one-based index into the SICN list. The location specifies
  213.     the top left corner of the SICN in the local coordinates of the
  214.     current port. Adapted from the THINK Class Library utilities. */
  215. void DrawSICN(Handle sicn, Point pt, short index)
  216. {
  217.     SignedByte state = 0;
  218.     BitMap    image;
  219.     Rect        bounds;
  220.     GrafPtr    port = NULL;
  221.     
  222.     require(index >= 1);
  223.     require(HandleSize(sicn) >= 32 * (index - 1));
  224.     state = HandleLock(sicn);
  225.     GetPort(&port);
  226.     image.baseAddr = *sicn + 32 * (index - 1);
  227.     image.rowBytes = 2;
  228.     SetRect(&bounds, pt.h, pt.v, pt.h + 16, pt.v + 16);
  229.     image.bounds = bounds;
  230.     CopyBits(&image, &port->portBits, &bounds, &bounds, srcCopy, NULL);
  231.     HandleRestore(sicn, state);
  232. }
  233.  
  234. /*    DrawIcon is like PlotIcon except that it operates on an 'ICN#'
  235.     resource instead of an 'ICON' resource. Also, before the icon
  236.     is drawn, a hole is punched using the icon's mask. DrawIcon should
  237.     work on all versions of the Macintosh since it is used to draw an
  238.     INIT's loaded/not loaded icon at the bottom of the screen. */
  239. void DrawIcon(Handle icon, Point pt)
  240. {
  241.     SignedByte    state = 0;
  242.     BitMap        srcBits;
  243.     Rect            srcRect;
  244.     Rect            dstRect;
  245.     GrafPtr        port = NULL;
  246.     
  247.     require(HandleSize(icon) >= 256);
  248.     state = HandleLock(icon);
  249.     SetRect(&dstRect, pt.h, pt.v, pt.h + 32, pt.v + 32);
  250.     GetPort(&port);
  251.     srcBits.baseAddr = *icon + 128;
  252.     srcBits.rowBytes = 4;
  253.     SetRect(&srcRect, 0, 0, 32, 32);
  254.     srcBits.bounds = srcRect;
  255.     CopyBits(&srcBits, &port->portBits, &srcRect, &dstRect, srcBic, 0);
  256.     srcBits.baseAddr = *icon;
  257.     CopyBits(&srcBits, &port->portBits, &srcRect, &dstRect, srcOr, 0);
  258.     HandleRestore(icon, state);
  259. }
  260.  
  261. /*----------------------------------------------------------------------*/
  262. /* invalidating regions and rectangles */
  263. /*----------------------------------------------------------------------*/
  264.  
  265. /* Invalidate and erase the region which is not common to both regions.
  266.     This is most useful when resizing an object or window, since
  267.     it invalidates only the region that has changed. */
  268. void InvalXorRgn(RgnHandle rgn1, RgnHandle rgn2)
  269. {
  270.     RgnHandle xor;
  271.  
  272.     xor  = BeginRgn();
  273.     XorRgn(rgn1, rgn2, xor);
  274.     InvalRgn(xor);
  275.     EraseRgn(xor);
  276.     EndRgn(xor);
  277. }
  278.  
  279. /* same as InvalXorRgn but operates on rectangles */
  280. void InvalXorRect(const Rect *r1, const Rect *r2)
  281. {
  282.     RgnHandle rgn1, rgn2;
  283.     
  284.     require(RectValid(r1));
  285.     require(RectValid(r2));
  286.     rgn1 = BeginRgn();
  287.     rgn2 = BeginRgn();
  288.     RectRgn(rgn1, r1);
  289.     RectRgn(rgn2, r2);
  290.     InvalXorRgn(rgn1, rgn2);
  291.     EndRgn(rgn1);
  292.     EndRgn(rgn2);
  293. }
  294.  
  295. /*----------------------------------------------------------------------*/
  296. /* drawing borders */
  297. /*----------------------------------------------------------------------*/
  298.  
  299. void BorderRgn(const Rect *content, short width, short margin,
  300.     Boolean visible, RgnHandle rgn)
  301. {
  302.     RgnHandle inner, outer;
  303.     Rect bounds;
  304.     
  305.     require(RectValid(content));
  306.     require(ValidateRgn(rgn));
  307.     require(width >= 0);
  308.     require(margin >= 0);
  309.     /* Return a region describing the frame rectangle (including the
  310.         one border between it and the object it encloses). This is useful
  311.         when you need to invalidate the border after an object has been
  312.         moved or resized. */
  313.     inner = BeginRgn();
  314.     outer = BeginRgn();
  315.     bounds = *content;
  316.     if (visible)
  317.         InsetRect(&bounds, width, width);
  318.     RectRgn(outer, &bounds);
  319.     if (! visible)
  320.         InsetRect(&bounds, width, width);
  321.     InsetRect(&bounds, margin, margin);
  322.     RectRgn(inner, &bounds);
  323.     DiffRgn(outer, inner, rgn);
  324.     EndRgn(inner);
  325.     EndRgn(outer);
  326. }
  327.  
  328. void BorderDraw(const Rect *content, short width, short margin,
  329.     Boolean visible)
  330. {
  331.     RgnHandle rgn;
  332.     PenState pen;
  333.     Rect bounds;
  334.     
  335.     require(RectValid(content));
  336.     require(width >= 0);
  337.     require(margin >= 0);
  338.     rgn = BeginRgn();
  339.     GetPenState(&pen);
  340.     PenNormal();
  341.     bounds = *content;
  342.     BorderRgn(&bounds, width, margin, visible, rgn);
  343.     EraseRgn(rgn);
  344.     if (visible) {
  345.         check(width > 0);
  346.         PenSize(width, width);
  347.         FrameRect(&bounds);
  348.     }
  349.     EndRgn(rgn);
  350.     SetPenState(&pen);
  351. }
  352.  
  353. /*----------------------------------------------------------------------*/
  354. /* dragging regions and rectangles */
  355. /*----------------------------------------------------------------------*/
  356.  
  357. /* Drag a gray outline of dragRgn. This function is used to drag
  358.     windows and floating menus. The parameters are:
  359.     
  360.     dragRgn    On entry, region to drag around, on exit moved to final
  361.                 position
  362.                 
  363.     frameRgn    When the mouse is released, if frameRgn doesn't intersect deskRgn
  364.                 then {0,0} is returned. FrameRgn maintains its position relative
  365.                 to dragRgn, so on exit it is also moved to its final position.
  366.                 FrameRgn is typically the drag region of a window.
  367.     
  368.     deskRgn    Region enclosing desktop; typically the value of
  369.                 GetGrayRgn().
  370.     
  371.     limitRgn    Region enclosed by desktop. If the mouse leaves limitRgn
  372.                 then the gray outline of dragRgn is hidden, though the mouse
  373.                 is still tracked. If the mouse is released outside of limitRgn,
  374.                 then {0,0} is returned.
  375.     
  376.     contRgn    The region within which to continue dragging. If the mouse
  377.                 leaves contRgn the function immediately returns {0,0}.
  378.     
  379.     clipRgn    The clip region of the port that dragging takes place in is
  380.                 set to clipRgn. The clip region is restored before the
  381.                 function returns.
  382.     
  383.     port        The graf port to draw into, typically the window manager port.
  384.     
  385.     startPt    The location of the mouse.
  386.     
  387.     It is very hard to explain this function without a diagram.
  388.     This comment is accurate as of 93/12/03 */
  389. Point DragRgn(RgnHandle dragRgn, RgnHandle frameRgn,
  390.     const RgnHandle deskRgn, const RgnHandle limitRgn,
  391.     const RgnHandle contRgn, const RgnHandle clipRgn,
  392.     GrafPtr port, Point startPt)
  393. {
  394.     PenState pen;                    /* saved pen state */
  395.     Point newPt, oldPt;            /* current and previous mouse positions */
  396.     Point offset = { 0, 0 };    /* result */
  397.     Boolean visible = false;    /* true if outline is visible */
  398.     volatile RgnHandle svclipRgn = NULL;    /* saved clip region */
  399.     volatile GrafPtr savePort = NULL;        /* saved port */
  400.     
  401.     require(ValidateRgn(dragRgn));
  402.     require(ValidateRgn(frameRgn));
  403.     require(ValidateRgn(deskRgn));
  404.     require(ValidateRgn(limitRgn));
  405.     require(ValidateRgn(contRgn));
  406.     require(ValidateRgn(clipRgn));
  407.     require(MemValid(port));
  408.     if (! StillDown())
  409.         return(offset); /* quick out */
  410.     TRY {
  411.  
  412.         /* setup port */
  413.         GetPort(&savePort);
  414.         SetPort(port);
  415.  
  416.         /* setup pen */
  417.         GetPenState(&pen);
  418.         PenNormal();
  419.         PenPat(gray);
  420.         PenMode(patXor);
  421.  
  422.         /* set clip region */
  423.         svclipRgn = BeginRgn();
  424.         GetClip(svclipRgn);
  425.         SetClip(clipRgn);
  426.         
  427.         /* draw outline */
  428.         if (PtInRgn(startPt, limitRgn) && PtInRgn(startPt, contRgn)) {
  429.             FrameRgn(dragRgn);
  430.             visible = true;
  431.         }
  432.  
  433.         /* drag outline */
  434.         newPt = oldPt = startPt;
  435.         while (StillDown() && PtInRgn(newPt, contRgn)) {
  436.  
  437.             /* get new mouse position */
  438.             GetMouse(&newPt);
  439.             LocalToGlobal(&newPt);
  440.             if (newPt.h != oldPt.h || newPt.v != oldPt.v) {
  441.  
  442.                 /* erase old outline and draw new outline */
  443.                 if (visible)
  444.                     FrameRgn(dragRgn);
  445.                 visible = false;
  446.                 OffsetRgn(dragRgn, newPt.h - oldPt.h, newPt.v - oldPt.v);
  447.                 OffsetRgn(frameRgn, newPt.h - oldPt.h, newPt.v - oldPt.v);
  448.                 if (PtInRgn(newPt, limitRgn)) {
  449.                     FrameRgn(dragRgn);
  450.                     visible = true;
  451.                 }
  452.                 oldPt = newPt;
  453.             }
  454.         }
  455.         
  456.         /* erase outline */
  457.         if (visible)
  458.             FrameRgn(dragRgn);
  459.         visible = false;
  460.         
  461.         /* calculate offset if mouse was released in a valid destination region */
  462.         if (PtInRgn(newPt, contRgn) && PtInRgn(newPt, limitRgn)) {
  463.             SectRgn(frameRgn, deskRgn, frameRgn);
  464.             if (! EmptyRgn(frameRgn)) {
  465.                 offset.h = newPt.h - startPt.h;
  466.                 offset.v = newPt.v - startPt.v;
  467.             }
  468.         }
  469.     } CLEANUP {
  470.         SetPenState(&pen);
  471.         if (svclipRgn) {
  472.             SetClip(svclipRgn);
  473.             EndRgn(svclipRgn);
  474.         }
  475.         if (savePort)
  476.             SetPort(savePort);
  477.     } ENDTRY;
  478.     return(offset);
  479. }
  480.  
  481. /* drag a rectangle around; see DragRgn for more details */
  482. Point DragRect(const Rect *dragRect, const Rect *frameRect, 
  483.     const RgnHandle contRgn, const RgnHandle clipRgn, Point startPt)
  484. {
  485.     Point offset = { 0, 0 };    /* change in position */
  486.     GrafPtr wmgrPort = NULL;    /* window manager's port */
  487.     RgnHandle dragRgn = NULL;    /* outline of region to drag */
  488.     RgnHandle frameRgn = NULL;    /* frame around region to drag */
  489.     RgnHandle limitRgn = NULL;    /* region within which to drag */
  490.     
  491.     require(RectValid(dragRect));
  492.     require(RectValid(frameRect));
  493.     require(ValidateRgn(contRgn));
  494.     require(ValidateRgn(clipRgn));
  495.     if (! StillDown())
  496.         return(offset); /* quick out */
  497.     dragRgn = BeginRgn(); RectRgn(dragRgn, dragRect);
  498.     frameRgn = BeginRgn(); RectRgn(frameRgn, frameRect);
  499.     limitRgn = BeginRgn(); CopyRgn(GetGrayRgn(), limitRgn);
  500.     InsetRgn(limitRgn, SCREEN_MARGIN, SCREEN_MARGIN);
  501.     GetWMgrPort(&wmgrPort);
  502.     offset = DragRgn(dragRgn, frameRgn, GetGrayRgn(), limitRgn,
  503.         contRgn, clipRgn, wmgrPort, startPt);
  504.     EndRgn(dragRgn);
  505.     EndRgn(frameRgn);
  506.     EndRgn(limitRgn);
  507.     return(offset);
  508. }
  509.